﻿namespace Smart.Utils.Net
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Runtime.CompilerServices;
    using System.Threading;

    public class FileDownloader
    {
        private bool canceled = false;
        private const int downloadBlockSize = 0x400;
        private string downloadingTo;
        private IWebProxy proxy = null;

        public event EventHandler DownloadComplete;

        public event DownloadProgressHandler ProgressChanged;

        public void AsyncDownload(List<string> urlList)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.WaitCallbackMethod), new object[] { urlList, "" });
        }

        public void AsyncDownload(string url)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.WaitCallbackMethod), new string[] { url, "" });
        }

        public void AsyncDownload(List<string> urlList, string destFolder)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.WaitCallbackMethod), new object[] { urlList, destFolder });
        }

        public void AsyncDownload(string url, string destFolder)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.WaitCallbackMethod), new string[] { url, destFolder });
        }

        public void Cancel()
        {
            this.canceled = true;
        }

        public void Download(List<string> urlList)
        {
            this.Download(urlList, "");
        }

        public void Download(string url)
        {
            this.Download(url, "");
        }

        public void Download(List<string> urlList, string destFolder)
        {
            if (urlList == null)
            {
                throw new ArgumentException("Url list not specified.");
            }
            if (urlList.Count == 0)
            {
                throw new ArgumentException("Url list empty.");
            }
            Exception exception = null;
            foreach (string str in urlList)
            {
                exception = null;
                try
                {
                    this.Download(str, destFolder);
                }
                catch (Exception exception2)
                {
                    exception = exception2;
                }
                if (exception == null)
                {
                    break;
                }
            }
            if (exception != null)
            {
                throw exception;
            }
        }

        public void Download(string url, string destFolder)
        {
            DownloadData data = null;
            this.canceled = false;
            try
            {
                int num;
                data = DownloadData.Create(url, destFolder, this.proxy);
                string fileName = Path.GetFileName(data.Response.ResponseUri.ToString());
                destFolder = destFolder.Replace("file:///", "").Replace("file://", "");
                this.downloadingTo = Path.Combine(destFolder, fileName);
                if (!System.IO.File.Exists(this.downloadingTo))
                {
                    System.IO.File.Create(this.downloadingTo).Close();
                }
                byte[] buffer = new byte[0x400];
                long startPoint = data.StartPoint;
                bool flag = false;
                while ((num = data.DownloadStream.Read(buffer, 0, 0x400)) > 0)
                {
                    if (this.canceled)
                    {
                        flag = true;
                        data.Close();
                        break;
                    }
                    startPoint += num;
                    this.SaveToFile(buffer, num, this.downloadingTo);
                    if (data.IsProgressKnown)
                    {
                        this.RaiseProgressChanged(startPoint, data.FileSize);
                    }
                    if (this.canceled)
                    {
                        flag = true;
                        data.Close();
                        break;
                    }
                }
                if (!flag)
                {
                    this.OnDownloadComplete();
                }
            }
            catch (UriFormatException exception)
            {
                throw new ArgumentException(string.Format("Could not parse the URL \"{0}\" - it's either malformed or is an unknown protocol.", url), exception);
            }
            finally
            {
                if (data != null)
                {
                    data.Close();
                }
            }
        }

        private void OnDownloadComplete()
        {
            if (this.DownloadComplete != null)
            {
                this.DownloadComplete(this, new EventArgs());
            }
        }

        private void RaiseProgressChanged(long current, long target)
        {
            if (this.ProgressChanged != null)
            {
                this.ProgressChanged(this, new DownloadEventArgs(target, current));
            }
        }

        private void SaveToFile(byte[] buffer, int count, string fileName)
        {
            FileStream stream = null;
            try
            {
                stream = System.IO.File.Open(fileName, FileMode.Append, FileAccess.Write);
                stream.Write(buffer, 0, count);
            }
            catch (ArgumentException exception)
            {
                throw new ArgumentException(string.Format("Error trying to save file \"{0}\": {1}", fileName, exception.Message), exception);
            }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
        }

        private void WaitCallbackMethod(object data)
        {
            if (data is string[])
            {
                string[] strArray = data as string[];
                this.Download(strArray[0], strArray[1]);
            }
            else
            {
                object[] objArray = data as object[];
                List<string> urlList = objArray[0] as List<string>;
                string destFolder = objArray[1] as string;
                this.Download(urlList, destFolder);
            }
        }

        public string DownloadingTo
        {
            get
            {
                return this.downloadingTo;
            }
        }

        public IWebProxy Proxy
        {
            get
            {
                return this.proxy;
            }
            set
            {
                this.proxy = value;
            }
        }
    }
}

